package singleton

import (
	"fmt"
	"os"
	"path/filepath"
	"sync"

	"gopkg.in/yaml.v3"
)

// config 结构体存放解析后的配置，首字母小写保证包外无法直接实例化。
type config struct {
	App struct {
		Name    string `yaml:"name"`
		Version string `yaml:"version"`
	} `yaml:"app"`
	Storage struct {
		Host string `yaml:"host"`
		Port int    `yaml:"port"`
	} `yaml:"storage"`
}

// cfg 保存单例实例；mu 用于并发场景下的互斥保护。
var (
	cfg *config
	mu  sync.Mutex
)

// GetConfig 演示传统双重检查锁定（Double-Checked Locking）。
// 1. 快路径：如果 cfg 已创建，直接返回，避免加锁开销。
// 2. 慢路径：cfg == nil 时加锁，再次判空后初始化。
func GetConfig() (*config, error) {
	if cfg != nil { // 第一重检查：绝大多数情况下直接返回
		return cfg, nil
	}

	mu.Lock()
	defer mu.Unlock()

	if cfg != nil { // 第二重检查：防止并发情况下重复初始化
		return cfg, nil
	}

	newCfg, err := loadConfigFromFile()
	if err != nil {
		return nil, err
	}
	cfg = newCfg
	return cfg, nil
}

// loadConfigFromFile 模拟耗时资源操作（读取并解析 YAML）。
func loadConfigFromFile() (*config, error) {
	path := filepath.Join(".", "config.yaml")
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("read config: %w", err)
	}

	var c config
	if err := yaml.Unmarshal(data, &c); err != nil {
		return nil, fmt.Errorf("parse config: %w", err)
	}
	return &c, nil
}
